// 请求不应该依赖其他包, 这样才方便架构解耦, 下载器部分
// 就可以选择不同的 http client crate 来实现
// 但是 `Request` 的成员参考一下 reqwest::RequestBuilder 的方法

use crate::component::response::Response;
use crate::component::{Headers, ParseResult};
use std::collections::HashMap;
use url::Url;

pub type FnParser<ItemType> =
    fn(resp: Response<ItemType>, metadata: Option<ItemType>) -> ParseResult<ItemType>;

/// 目前就支持两个 GET, POST
#[derive(Clone)]
pub enum Method {
    GET,
    POST,
}

#[derive(Clone)]
pub enum RequestBody {
    Form(HashMap<String, String>),
    Json(ureq::SerdeValue),
    Bytes(Vec<u8>),
    Empty,
}

/// 请求结构体
#[derive(Clone)]
pub struct Request<ItemType: Clone> {
    pub url: Url,
    pub method: Method,
    pub headers: Headers,
    // ?a=b&c=d
    pub query: Option<HashMap<String, String>>,
    // 相当于 form
    pub body: RequestBody,
    pub parser: Option<FnParser<ItemType>>,
    pub metadata: Option<ItemType>,
}

impl<ItemType: Clone> Request<ItemType> {
    pub fn new(
        url: Url,
        method: Method,
        headers: Headers,
        query: Option<HashMap<String, String>>,
        body: RequestBody,
        parser: Option<FnParser<ItemType>>,
        metadata: Option<ItemType>,
    ) -> Self {
        Self {
            url,
            method,
            headers,
            query,
            body,
            parser,
            metadata,
        }
    }

    pub fn simple_get(
        url: Url,
        query: Option<HashMap<String, String>>,
        parser: Option<FnParser<ItemType>>,
    ) -> Self {
        Self {
            url,
            method: Method::GET,
            headers: Headers::new(vec![]),
            query,
            body: RequestBody::Empty,
            parser,
            metadata: None,
        }
    }

    pub fn simple_post(url: Url, body: RequestBody, parser: Option<FnParser<ItemType>>) -> Self {
        Self {
            url,
            method: Method::POST,
            headers: Headers::new(vec![]),
            query: None,
            body,
            parser,
            metadata: None,
        }
    }
}

// TODO: 一些方法 //
